/*
 ============================================================================
 Name        pfs: fat.c
 Author      : superacidos
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include "fat.h"
#include "log.h"
#include <string.h>
#include <errno.h>
#include "config.h"
#include <ctype.h>

extern struct bootsector bs;
extern struct fatCache fat_cache;
extern struct stConfig config;
extern pthread_mutex_t semaforoFatRegion;


int32_t fat_load (int32_t numBloqueFat)
{
	//Carga la Fat Region en memoria, por ahora estamo cargando toda

	int32_t bloquesPorBloqueFat = BYTESFATCACHE / BYTESPERSEC / SECPERBLOQ;
	int32_t bloqueComienzoBloquePedido = (*bs.rsvdseccnt / SECPERBLOQ) + numBloqueFat * bloquesPorBloqueFat;
	int32_t i,offset;

	unsigned char *contenidoBloque;


	for(i=0;i<bloquesPorBloqueFat; i++)
	{
		offset = i * BYTESPERSEC * SECPERBLOQ;
		contenidoBloque = obtenerBloque(bloqueComienzoBloquePedido + i);
		memcpy(fat_cache.data + offset, contenidoBloque, BYTESPERSEC * SECPERBLOQ);
		free (contenidoBloque);
	}

	//Actualizo datos fat_cache
	fat_cache.numBloqueFat = numBloqueFat;
	fat_cache.modificado = 0;

	return 1;

}

int32_t fat_flush ()
{
	int32_t bloquesPorBloqueFat = BYTESFATCACHE / BYTESPERSEC / SECPERBLOQ;
		int32_t bloqueComienzoBloquePedido = (*bs.rsvdseccnt / SECPERBLOQ) + fat_cache.numBloqueFat * bloquesPorBloqueFat;
		int32_t i,offset;

		unsigned char *contenidoBloque;

		for(i=0;i<bloquesPorBloqueFat; i++)
		{
			offset = i * BYTESPERSEC * SECPERBLOQ;
			escribirBloque(bloqueComienzoBloquePedido + i, fat_cache.data + offset);
		}

		//Actualizo datos fat_cache
		fat_cache.modificado = 0;

	return 1;

}

unsigned char *leerFatRegion(int32_t numCluster)
{

	//El semaforo de Fat Region va en las funciones que llaman a esta
	int32_t numBloqueFatCache = calcularBloqueFat(numCluster);
	if(fat_cache.numBloqueFat != numBloqueFatCache)
	{
		if(fat_cache.modificado == 1)
		{
			fat_flush();
		}
		fat_load(numBloqueFatCache);
	}

	return fat_cache.data;
}

unsigned char *leerClusterDataRegionArchivo(ARCHIVO *arch, int32_t numCluster)
{
	unsigned char *cluster;

	if(config.tamanioCache != 0)
	{

		if(config.tamanioCache > 0)
		//traigo de cache y si devuelve 0 es que no lo encontro
		cluster = malloc(BYTESPERSEC * *bs.secperclus);
		if(!cache_archivo_leer(arch,numCluster,cluster))
		{
			free(cluster);
			cluster = leerClusterDataRegion(numCluster);
			cache_archivo_escribir(arch,numCluster,cluster);
		}

	}else
	{
		cluster = leerClusterDataRegion(numCluster);

	}


	return cluster;
}

unsigned char *leerClusterDataRegion(int32_t numCluster)
{
	//aca vamos a tener que pedir la cantidad de bloques de 1 k que den un cluster
	int32_t numBloque = calcularPrimerBloqueDeCluster(numCluster);

	unsigned char *cluster = malloc(sizeof(char)*512*8);

	unsigned char *bloque1 = obtenerBloque(numBloque);
	memcpy(cluster, bloque1, 1024);
	free(bloque1);

	numBloque++;
	unsigned char *bloque2 = obtenerBloque(numBloque);
	memcpy(cluster+1024, bloque2, 1024);
	free(bloque2);

	numBloque++;
	unsigned char *bloque3 = obtenerBloque(numBloque);
	memcpy(cluster+2048, bloque3, 1024);
	free(bloque3);

	numBloque++;
	unsigned char *bloque4 = obtenerBloque(numBloque);
	memcpy(cluster+3072, bloque4, 1024);
	free(bloque4);

	return cluster;
}



int32_t modificarArchivo(ARCHIVO *arch, char *datos, int32_t offset, size_t size)
{
	int32_t tamanioAgregado;
	int32_t clusterDirectorio, numeroBytesEntradaCluster;
	int32_t cantidadClusters, cantClustersModificar;
	int32_t i = 1;
	int32_t primerClusterModificar, primerByteModificar;
	int32_t bytesEscritos = 0;
	int32_t tamanioCluster = *bs.secperclus * BYTESPERSEC;
	int32_t restante = 0;
	struct cluster *listaClusters;
	unsigned char *contenidoCluster;

	//Calculo el tamanio del agregado
	tamanioAgregado = size; //strlen(datos);
	//Calculo a partir de que cluster hay que modificar
	primerClusterModificar = abs(offset / tamanioCluster);
	primerByteModificar = offset - primerClusterModificar * tamanioCluster;

	//Agrando el tamanio del archivo
	int32_t clusterInicial;
	if((offset + tamanioAgregado) > arch->size)
	{
		arch->size = offset + tamanioAgregado;
		truncarArchivo(arch->path, arch->size, &clusterInicial);
		//Obtengo lista de clusters del archivo
		listaClusters = listaClustersEncadenados(clusterInicial, &cantidadClusters);
	}else
	{
		//Obtengo lista de clusters del archivo
		listaClusters = arch->listaClusters;
	}

	//Calculo cuantos clusters se modifican
	cantClustersModificar = abs(tamanioAgregado/tamanioCluster);

	if((tamanioAgregado % tamanioCluster) != 0)
	{
		cantClustersModificar ++;
	}


	//Avanzo hasta el cluster a modificar
	while(i-1 < primerClusterModificar)
	{
		listaClusters = listaClusters->sgt;
		i++;
	}
	contenidoCluster = malloc(tamanioCluster);
	*contenidoCluster = '\0';

	//Leo el primer cluster que cambia
	contenidoCluster = leerClusterDataRegionArchivo(arch, listaClusters->numCluster);
	//Si este no es el ultimo cluster
	if(cantClustersModificar > i)
	{
		memcpy(contenidoCluster + primerByteModificar, datos + bytesEscritos, tamanioCluster - primerByteModificar);
		EscribirClusterDataRegionArchivo(arch, listaClusters->numCluster, contenidoCluster);

		bytesEscritos = tamanioCluster - primerByteModificar;
		listaClusters = listaClusters->sgt;
		i++;

		while(cantClustersModificar > i)
		{
			*contenidoCluster = '\0';
			memcpy(contenidoCluster, datos + bytesEscritos, tamanioCluster);
			EscribirClusterDataRegionArchivo(arch,listaClusters->numCluster, contenidoCluster);

			bytesEscritos = bytesEscritos + tamanioCluster;
			listaClusters = listaClusters->sgt;
			i++;
		}

		*contenidoCluster = '\0';
		restante = tamanioAgregado - (cantClustersModificar - 1) * tamanioCluster;

		memcpy(contenidoCluster + primerByteModificar, datos + bytesEscritos, restante);
		EscribirClusterDataRegionArchivo(arch,listaClusters->numCluster, contenidoCluster);
	}
	else
	{
		memcpy(contenidoCluster + primerByteModificar, datos, tamanioAgregado);
		EscribirClusterDataRegionArchivo(arch,listaClusters->numCluster, contenidoCluster);
	}

	free(contenidoCluster);
	return size;
}

struct nodoLFN *listarDirectorioDataRegion(int32_t numCluster)
{
	//Imprime los nombres de archivo, directorio o lfn para un cluster

	unsigned char *nombreCompleto;
	unsigned char *entrada_utf16;
	unsigned char *entrada_utf8;
	char descripcionEntrada[100];
	int32_t i = 0;
	int32_t longitudUTF8 = 0;
	int32_t longitudParcial = 0;
	int32_t esDirectorio;
	unsigned char *primerCluster;
	struct nodoLFN *pri = NULL, *ult = NULL;

	//Obtengo la data del cluster entero
	unsigned char *cluster = leerClusterDataRegion(numCluster);

	nombreCompleto = malloc (255);
	entrada_utf16 = malloc(26);
	entrada_utf8 = malloc(26);
	primerCluster = malloc(4);

	*nombreCompleto = '\0';
	*entrada_utf16 = '\0';
	*entrada_utf8 = '\0';
	*primerCluster = '\0';

	//Voy avanzando de entrada en entrada (o sea de a 32 Bytes) hasta leer 0x00
	while (cluster[i] != 0x00 && i <= (*bs.secperclus*BYTESPERSEC))
	{
		if(cluster[i] == 0x2E || cluster[i] == 0xE5) //entrada '.' o '..' o eliminada
		{
			//Avanzo de entrada
			i += 32;
			continue;
		}
		//Si es LFN
		if(cluster[i + 11] == 0x0F)
		{
			//leo los bytes que contieneneal nombre
			memcpy(entrada_utf16, cluster + i + 1, 10);
			memcpy(entrada_utf16 + 10, cluster + i + 14, 12);
			memcpy(entrada_utf16 + 22, cluster + i + 28, 4);


			//Convierto a UTF8 y lo invierto
			unicode_utf16_to_utf8_inbuffer(entrada_utf16, 26, entrada_utf8, &longitudUTF8);
			strrev(entrada_utf8);

			//Voy acumulando el nombre de forma invertida
			memcpy(nombreCompleto + longitudParcial, entrada_utf8, strlen(entrada_utf8));
			nombreCompleto[longitudParcial + strlen(entrada_utf8)] = '\0';
			longitudParcial = strlen(nombreCompleto);

			*entrada_utf16 = '\0';
			*entrada_utf8 = '\0';
			*descripcionEntrada = '\0';

			i += 32;

			esDirectorio = 0;

			//identifico tipo de entrada
			switch (cluster[i+11])
			{
			case FILE_ATTR_READ_ONLY:
				strcpy(descripcionEntrada,"Read Only");
				break;
			case FILE_ATTR_HIDDEN:
				strcpy(descripcionEntrada,"Hidden");
				break;
			case FILE_ATTR_SYSTEM:
				strcpy(descripcionEntrada,"System");
				break;
			case FILE_ATTR_VOLUME_ID:
				strcpy(descripcionEntrada,"Volume Label");
				break;
			case FILE_ATTR_DIRECTORY:
				strcpy(descripcionEntrada,"Directory");
				esDirectorio = 1;
				break;
			case FILE_ATTR_ARCHIVE:
				strcpy(descripcionEntrada,"Archive");
				break;
			case FILE_ATTR_DEVICE:
				strcpy(descripcionEntrada,"Device");
				break;
			case FILE_ATTR_UNUSED:
				strcpy(descripcionEntrada,"Unused");
				break;
			}

			descripcionEntrada[strlen(descripcionEntrada)] = '\0';


			memcpy(primerCluster, cluster + i + 0x14, 2);
			memcpy(primerCluster + 2, cluster + i + 0x1A, 2);


			//Ya tengo el nombre completo asi que lo invierto nuevamente para imprimir
			strrev(nombreCompleto);

			nombreCompleto[13] = '\0';

			//Creo la lista
			ult = creaColaLFN(ult,nombreCompleto);
			if(pri == NULL)pri = ult;

			*nombreCompleto = '\0';
			longitudParcial = 0;
			*descripcionEntrada ='\0';
			*primerCluster = '\0';

		}
		else
		{
			// Es una entrada de directorio sin LFN
			int32_t m = 0;
			while(m<8 && cluster[i+m]!= ' ')
			{
				nombreCompleto[m] = cluster[i+m];
				m++;
			}

			esDirectorio = 0;

			//identifico tipo de entrada
			switch (cluster[i+11])
			{
			case FILE_ATTR_READ_ONLY:
				strcpy(descripcionEntrada,"Read Only");
				break;
			case FILE_ATTR_HIDDEN:
				strcpy(descripcionEntrada,"Hidden");
				break;
			case FILE_ATTR_SYSTEM:
				strcpy(descripcionEntrada,"System");
				break;
			case FILE_ATTR_VOLUME_ID:
				strcpy(descripcionEntrada,"Volume Label");
				break;
			case FILE_ATTR_DIRECTORY:
				strcpy(descripcionEntrada,"Directory");
				esDirectorio = 1;
				break;
			case FILE_ATTR_ARCHIVE:
				strcpy(descripcionEntrada,"Archive");
				break;
			case FILE_ATTR_DEVICE:
				strcpy(descripcionEntrada,"Device");
				break;
			case FILE_ATTR_UNUSED:
				strcpy(descripcionEntrada,"Unused");
				break;
			}

			descripcionEntrada[strlen(descripcionEntrada)] = '\0';


			memcpy(primerCluster, cluster + i + 0x14, 2);
			memcpy(primerCluster + 2, cluster + i + 0x1A, 2);

			if(!esDirectorio)
			{
				nombreCompleto[m] = '.';
				m++;
				memcpy(nombreCompleto + m, cluster + i + 8, 3);
				m += 3;
			}
			nombreCompleto[m] = '\0';

			//Creo la lista
			ult = creaColaLFN(ult,nombreCompleto);
			if(pri == NULL)pri = ult;

			*nombreCompleto = '\0';
			longitudParcial = 0;
			*descripcionEntrada ='\0';
			*primerCluster = '\0';


		}
		//Avanzo de entrada
		i += 32;
	}

	free(nombreCompleto);
	free(entrada_utf16);
	free(entrada_utf8);
	free(primerCluster);

	return pri;
}

int32_t buscarEnDirectorio(struct fat_dir_entry *entry, int32_t numClusterDirectorio, char *nombreBuscado, int32_t *numeroBytesEntradaCluster)
{
	//Busca una entrada en un directorio y devuelve el cluster su cluster inicial

	unsigned char *nombreCompleto;
	unsigned char *entrada_utf16;
	unsigned char *entrada_utf8;
	int32_t i = 0;
	int32_t encontrado = 0;
	int32_t longitudUTF8 = 0;
	int32_t longitudParcial = 0;
	unsigned char *primerCluster;

	//Obtengo la data del cluster entero
	unsigned char *cluster = leerClusterDataRegion(numClusterDirectorio);

	//Inicializo directoryEntry para identificar si quedo vacia
	//memcpy(directoryEntry->Attr, 'n',1);

	nombreCompleto = malloc (255);
	entrada_utf16 = malloc(26);
	entrada_utf8 = malloc(26);
	primerCluster = malloc(4);


	*nombreCompleto = '\0';
	*entrada_utf16 = '\0';
	*entrada_utf8 = '\0';
	*primerCluster = '\0';

	//Voy avanzando de entrada en entrada (o sea de a 32 Bytes) hasta leer 0x00
	while (cluster[i] != 0x00 && i <= (*bs.secperclus*BYTESPERSEC))
	{
		if(cluster[i] == 0x2E || cluster[i] == 0xE5) //entrada '.' o '..' o eliminada
		{
			//Avanzo de entrada
			i += 32;
			continue;
		}
		//Solo me intersa que sea LFN
		if(cluster[i + 11] == 0x0F)
		{
			//leo los bytes que contieneneal nombre
			memcpy(entrada_utf16, cluster + i + 1, 10);
			memcpy(entrada_utf16 + 10, cluster + i + 14, 12);
			memcpy(entrada_utf16 + 22, cluster + i + 28, 4);

			//Convierto a UTF8 y lo invierto
			unicode_utf16_to_utf8_inbuffer(entrada_utf16, 26, entrada_utf8, &longitudUTF8);
			strrev(entrada_utf8);

			//Voy acumulando el nombre de forma invertida
			memcpy(nombreCompleto + longitudParcial, entrada_utf8, strlen(entrada_utf8));
			nombreCompleto[longitudParcial + strlen(entrada_utf8)] = '\0';
			longitudParcial = strlen(nombreCompleto);

			*entrada_utf16 = '\0';
			*entrada_utf8 = '\0';

			i += 32;

			//Ya tengo el nombre completo asi que lo invierto nuevamente
			strrev(nombreCompleto);
			nombreCompleto[13] = '\0';

			if(strcmp(nombreCompleto,nombreBuscado) == 0)
			{
				//Leo entrada
				//	entry = malloc(sizeof(struct fat_dir_entry));
				memcpy(entry, cluster + i, sizeof(struct fat_dir_entry));
				*numeroBytesEntradaCluster = i;
				encontrado = 1;

				break;
			}



			*nombreCompleto = '\0';
			longitudParcial = 0;

		}
		else
		{
			//Es entrada de directorio sin LFN
			int32_t m = 0;
			while(m<8 && cluster[i+m]!= ' ')
			{
				nombreCompleto[m] = cluster[i+m];
				m++;
			}

			int32_t esDirectorio = 0;

			if(!esDirectorio)
			{
				nombreCompleto[m] = '.';
				m++;
				memcpy(nombreCompleto + m, cluster + i + 8, 3);
				m += 3;
			}
			nombreCompleto[m] = '\0';

			if(strcmp(nombreCompleto,nombreBuscado) == 0)
			{
				//Leo entrada
				//	entry = malloc(sizeof(struct fat_dir_entry));
				memcpy(entry, cluster + i, sizeof(struct fat_dir_entry));
				*numeroBytesEntradaCluster = i;
				encontrado = 1;

				break;
			}



			*nombreCompleto = '\0';
			longitudParcial = 0;


		}
		//Avanzo de entrada
		i += 32;
	}

	free(nombreCompleto);
	free(entrada_utf16);
	free(entrada_utf8);
	free(cluster);

	return encontrado;
}


/*** Helper: Funciones con Strings ****/

void borrarEspacios(char *ch, int32_t longitud){//NO SE ESTA USANDO
	int i,j=0;

	for(i=0;i<=longitud;i++){
		if(ch[i]!='\0' && ch[i]!= -1){
			ch[j] = ch[i];
			j++;
		}
	}
	ch[j] = '\0';
}

void strrev(char* str)
{
	int i;
	char cpstr[strlen(str)+1];
	int leng = strlen(str);
	for(i=0; i < strlen(str); i++)
	{
		//printf("%d\t%d\t", i, strlen(str)-i-1);
		cpstr[i] = str[strlen(str)-i-1];
	}
	cpstr[i] = '\0';
	strcpy(str, cpstr);

}

char * convertirMayusculas( char * pszCadena )
{
	char * pszAux = NULL ;

	for( pszAux = pszCadena; *pszAux; ++pszAux )
		*pszAux = toupper( *pszAux ) ;

	return( pszCadena );
}

/*** END Helper: Funciones con Strings ****/

int32_t EscribirEntradaFatRegion(int32_t numCluster, char *contenido)
{
	//esto tiene que escribir en cache
	unsigned char * fat_region = leerFatRegion(numCluster);
	int32_t offset = (numCluster * 4) % BYTESFATCACHE;
	//todo en caso de tener parte de la fat en memoria, tedriamos que ver bien como hacemos esto
	memcpy(fat_region+offset, contenido, 4);

	fat_cache.modificado = 1;

	return 1;
}

int32_t EscribirClusterDataRegionArchivo(ARCHIVO *arch, int32_t numCluster, unsigned char *contenidoCluster)
{
	if(config.tamanioCache != 0)
	{
		cache_archivo_escribir(arch,numCluster,contenidoCluster);

	}
	else
	{
		EscribirClusterDataRegion(numCluster,contenidoCluster);

	}


	return 1;


}

int32_t EscribirClusterDataRegion(int32_t numCluster, unsigned char *contenidoCluster)
{
	//todo esta escribiendo todo el cluster cuando podria escribir solo el bloque modificado
	//si llega a haber problemas de velocidad o abuso de conexiones convendria modificar

	int32_t cantBloquesXCluster = *bs.secperclus / SECPERBLOQ;
	int32_t primerBloque = calcularPrimerBloqueDeCluster(numCluster);
	int32_t cantBytesXBloque = BYTESPERSEC * SECPERBLOQ;
	int32_t i, offset;
	unsigned char *contenidoBloque;

	contenidoBloque = malloc(cantBytesXBloque);

	for(i=0;i<cantBloquesXCluster; i++)
	{
		offset = i*cantBytesXBloque;
		memcpy(contenidoBloque, contenidoCluster + offset, cantBytesXBloque);
		escribirBloque(primerBloque + i, contenidoBloque);
	}

	free(contenidoBloque);
	return 1;
}


int32_t leerClusterFATRegion(int32_t numCluster)
{
	//Traigo el bloque de fat donde esta el cluster que necesito

	int32_t offset, contenido;

	offset = numCluster % (BYTESFATCACHE / 4);

	unsigned char *fat_region = leerFatRegion(numCluster);

	contenido = GET_32BIT_WORD(fat_region, offset*4);

	return contenido;
}

int32_t calcularBloqueFat(int32_t numCluster)
{
	int32_t numBloqueFat, cantClustersXBloqueFat;

	cantClustersXBloqueFat = BYTESFATCACHE / 4; //Cada cluster ocupa 4 Bytes en FAT Region

	numBloqueFat = numCluster / cantClustersXBloqueFat;

	return numBloqueFat;
}

void logCadenaClusters(int32_t startcluster, int pid)
{
	int32_t i,cantidadClusters;
	struct cluster *listaClusters = listaClustersEncadenados(startcluster, &cantidadClusters);
	char stringClusters[200];
	char conversion[15];

	i = 0;

	strcpy(stringClusters,"#Clusters: ");

	while(i < cantidadClusters-1)
	{
		if(strlen(stringClusters)<=185)
		{
			sprintf(conversion, "%d", listaClusters->numCluster);
			strcat(stringClusters, conversion);
			strcat(stringClusters, ", ");
			listaClusters = listaClusters->sgt;
			i++;
		}
		else
		{
			if(config.loguear == 1)
			{
				logMessage("leerArchivo",pid,0,0,stringClusters);
			}
			stringClusters[0] = '\0';
		}
	}

	sprintf(conversion, "%d", listaClusters->numCluster);
	strcat(stringClusters, conversion);
	strcat(stringClusters, ".");
	if(config.loguear == 1)
	{
		logMessage("leerArchivo",pid,0,0,stringClusters);
	}
}


int32_t f_getattr(const char *path, struct stat *stbuf)
{
	int32_t res = 0, cluster, bytes;
	struct fat_dir_entry *entry;

	entry = obtenerEntradaDataRegion(path, &cluster, &bytes);
	memset(stbuf, 0, sizeof(struct stat));

	stbuf->st_nlink = 1;  //EN TODOS LADOS LO VI = 1
	stbuf->st_blksize  = BYTESPERSEC*2;  //TAMAÑO BLOQUE EN BYTES  (DOS SECTORES ES UN BLOQUE)
	stbuf->st_rdev= 0; //NO TENEMOS SPECIAL FILES
	stbuf->st_gid = getgid();
	stbuf->st_uid = getuid();


	if(entry->Attr == 0x10)//ES DIRECTORIO
	{
		stbuf->st_mode = S_IFDIR | 0755;
		stbuf->st_size = 0;
		stbuf->st_blocks = 0;
	}
	else if(entry->Attr == 0x20)//ES ARCHIVO
	{
		stbuf->st_mode = S_IFREG | entry->Attr;
		stbuf->st_blocks = 4; //MANEJO TODO CON CLUSTERS.  4 BLOQUES ES UN CLUSTER.
		stbuf->st_size = entry->FileSize;

	}
	else
	{
		free(entry);
		return -ENOENT;
	}
	free(entry);
	return res;


}

unsigned char *leerArchivo(ARCHIVO *arch, size_t tamanioPedido,  off_t offset)
{
	int32_t i, pos, bytesXCluster, bytesUltimoCluster,bytesOffset;
	int32_t indiceClusterOffset, cantClustersALeer, sobrante;
	cantClustersALeer = 0;
	struct cluster *cluster;
	unsigned char *archivo, *contenidoCluster;


	bytesXCluster = *bs.secperclus * BYTESPERSEC;

	bytesOffset = offset % bytesXCluster;

	indiceClusterOffset = offset /  bytesXCluster;

	sobrante = bytesXCluster - bytesOffset;
	if(sobrante == 0 || tamanioPedido > sobrante)
	{
		cantClustersALeer = (tamanioPedido - sobrante) / bytesXCluster;
		//Si no da exacto la division sumo uno
		if((tamanioPedido - sobrante) > (cantClustersALeer * bytesXCluster))
		{
			cantClustersALeer ++;
		}
	}
	//Si el offset no es al comienzo de un cluster sumo uno
	if(sobrante != 0)
	{
		cantClustersALeer ++;
	}

	//Cant bytes que quedan leer en el ultimo cluster
	bytesUltimoCluster = (tamanioPedido-sobrante) % bytesXCluster;
	if(bytesUltimoCluster == 0 )
	{
		bytesUltimoCluster = bytesXCluster;
	}

	archivo = malloc(cantClustersALeer * bytesXCluster);

	cluster = arch->listaClusters;

	//Voy hasta el cluster del offset
	for(i=0; i < indiceClusterOffset; i++)
	{
		cluster = cluster->sgt;
	}
	//Leo la data
	//Primer cluster a leer
	if(sobrante != 0)
	{
		contenidoCluster = leerClusterDataRegionArchivo(arch, cluster->numCluster);
		memcpy(archivo, contenidoCluster + bytesOffset,sobrante);
		free(contenidoCluster);
		cluster = cluster->sgt;
	}
	//Clusters del medio
	for(i=1; i < cantClustersALeer-1; i++)
	{
		pos = (i-1) * bytesXCluster + sobrante;
		contenidoCluster = leerClusterDataRegionArchivo(arch, cluster->numCluster);
		memcpy(archivo + pos, contenidoCluster,bytesXCluster);
		free(contenidoCluster);
		cluster = cluster->sgt;
	}
	//Ultimo cluster
	if(cantClustersALeer > 1)
	{
		pos = (i-1) * bytesXCluster + sobrante;
		contenidoCluster = leerClusterDataRegionArchivo(arch, cluster->numCluster);
		memcpy(archivo + pos,contenidoCluster ,bytesUltimoCluster);
		free(contenidoCluster);
	}
	//Fin leo data

	//Agrego carcater fin datos
	archivo[tamanioPedido + 1] = '/0';

	return archivo;

}

int32_t obtenerClusterInicial(char *pathArchivo)
{
	int32_t clusterInicial = 0, clusterDirectorio, numeroBytesEntradaCluster;
	if(strcmp(pathArchivo,"/")==0)
	{
		clusterInicial = 2;
	}
	else
	{
		struct fat_dir_entry *directoryEntry = obtenerEntradaDataRegion(pathArchivo,&clusterDirectorio, &numeroBytesEntradaCluster);
		if(!directoryEntry)
		{
			clusterInicial = 0;
		}
		else
		{
			if((directoryEntry->FstClusHI == 0) && (directoryEntry->FstClusLO== 0))
			{
				clusterInicial =  2;
			}
			else
			{
				clusterInicial = swap_uint32(directoryEntry->FstClusHI) + directoryEntry->FstClusLO;
			}
			free(directoryEntry);
		}
	}
	return clusterInicial;
}

struct fat_dir_entry *obtenerEntradaDataRegion(char *pathArchivo, int32_t *clusterDirectorio, int32_t *numeroBytesEntradaCluster)
{
	int32_t clusterInicial=*clusterDirectorio=2;
	int32_t i = 0, existe;
	char **split;
	struct fat_dir_entry *directoryEntry;
	directoryEntry = malloc(sizeof(struct fat_dir_entry));

	split = string_split2(pathArchivo,'/');
	while(split[i] != NULL)
	{
		existe = buscarEnDirectorio(directoryEntry,clusterInicial,split[i],numeroBytesEntradaCluster);
		//Pregunto si encontro la entrada (directorio/archivo)
		if(!existe)
		{
			directoryEntry = NULL;
			break;
		}

		*clusterDirectorio = clusterInicial;
		clusterInicial = swap_uint32(directoryEntry->FstClusHI) + directoryEntry->FstClusLO;
		i++;
	}

	return directoryEntry;

}




int32_t truncarArchivo(char *pathArchivo, int32_t tamanioNuevo, int32_t *clusterInicialADevolver)
{
	struct cluster *cadenaClusters;
	int32_t tamanioCluster = *bs.secperclus * BYTESPERSEC;
	int32_t clusterDirectorio,numeroBytesEntradaCluster, cantClustersActual,cantClustersNueva, diferencia, i;
	uint32_t clusterInicial;
	unsigned char *contenidoCluster;
	struct fat_dir_entry *directoryEntry;
	char *contenido;
	contenido = malloc(sizeof(char)*4);

	//Calcular clusters a ocupar

	cantClustersNueva = abs(tamanioNuevo/tamanioCluster);

	if((tamanioNuevo % tamanioCluster) != 0)
	{
		cantClustersNueva ++;
	}

	directoryEntry = obtenerEntradaDataRegion(pathArchivo, &clusterDirectorio, &numeroBytesEntradaCluster);


	//Bloqueo semaforo de Fat Region
	pthread_mutex_lock(&semaforoFatRegion);

	if(directoryEntry->FileSize != 0)
	{
		clusterInicial = swap_uint32(directoryEntry->FstClusHI) + directoryEntry->FstClusLO;

		//listaClustersEncadenados bloquea de nuevo asi que aca desbloqueo y vuelvo a bloquear despues
		//Desbloqueo semaforo de Fat Region
		pthread_mutex_unlock(&semaforoFatRegion);

		cadenaClusters = listaClustersEncadenados(clusterInicial, &cantClustersActual);

		//Bloqueo semaforo de Fat Region
		pthread_mutex_lock(&semaforoFatRegion);
	}
	else
	{
		clusterInicial = agregarClusterACadena(-1);//(-1: Crea nueva cadena) devuelve el cluster que agrego

		if(clusterInicial == -1)
		{
			//No pudo crear la cadena
			//Desbloqueo semaforo de Fat Region
			pthread_mutex_unlock(&semaforoFatRegion);

			return 1; //Error
		}

		unsigned short clusterLO;
		unsigned short clusterHI;
		clusterLO = clusterInicial & 0x0000FFFF;
		clusterHI = clusterInicial >> 16;

		//Escribo en la entrada del archivo la dir del primer cluster
		directoryEntry->FstClusLO = clusterLO;
		directoryEntry->FstClusHI = clusterHI;

		cantClustersActual = 1;
	}

	diferencia = cantClustersNueva - cantClustersActual;

	//elimino o agrego (si el tamaño es mayor) de la cadena en la FAT, modificando el EOC

	if(diferencia > 0)
	{
		for(i=0; i<diferencia; i++)
		{
			agregarClusterACadena(clusterInicial);
		}
	}
	else
	{
		for(i=0; i>diferencia; i--)
		{
			eliminarClusterDeCadena(clusterInicial);
		}
	}

	//Asigno nuevo valor al tamaño

	directoryEntry->FileSize = tamanioNuevo;
	if(tamanioNuevo == 0)
	{
		directoryEntry->FstClusHI = 0;
		directoryEntry->FstClusLO = 0;
	}

	//Flush de la fat region
	fat_flush();

	//Desbloqueo semaforo de Fat Region
	pthread_mutex_unlock(&semaforoFatRegion);

	//Actualizo la entrada de archivo
	contenidoCluster = malloc(tamanioCluster);
	contenidoCluster = leerClusterDataRegion(clusterDirectorio);

	memcpy(contenidoCluster+numeroBytesEntradaCluster,directoryEntry,32);

	EscribirClusterDataRegion(clusterDirectorio, contenidoCluster);

	*clusterInicialADevolver = clusterInicial;

	free(contenido);
	free(contenidoCluster);
	return 0;


}

void eliminarEntradaDataRegion(unsigned char *cluster, int32_t numEntrada)
{
	//poner la entrada en 0xE5
	cluster[numEntrada] = 0xE5;


}

int32_t renombrarArchivo(char *pathInicial, char *nuevoNombre)
{
	//encontrar el lfn y entrada directorio en el dataregion y marcarlos como eliminados
	//encontrar espacio para dos entradas de directorio nuevas y crearlas, con el nuevo nombre

	int32_t i = 0;
	int32_t j = 0;
	int32_t k = 0;
	int32_t y;
	unsigned char *nombreCompleto;
	unsigned char *entrada_utf16;
	unsigned char *entrada_utf8;
	int32_t longitudUTF8 = 0;
	int32_t longitudParcial = 0;
	int32_t clusterDir;
	int32_t clusterDirNuevo;
	char *nombreArchivo;
	char *pathArchivo;
	char *nombreNuevo;
	char *pathNuevo;
	char *ultimaBarra;


	nombreArchivo = malloc(13);
	pathArchivo = malloc(255);
	nombreArchivo[0]='\0';
	pathArchivo[0]='\0';

	nombreNuevo = malloc(13);
	pathNuevo = malloc(255);
	nombreNuevo[0]='\0';
	pathNuevo[0]='\0';

	//Calculo nivel donde esta ubicado el archivo
	while(pathInicial[k] != NULL)
	{
		if(pathInicial[k] == '/')
		{
			j++;
		}
		k++;
	}

	k=0;
	//Separo el nombre del directorio y el archivo si no es carpeta raiz
	if(j > 0)
	{
		ultimaBarra = strrchr(pathInicial,'/');
		while(pathInicial+i != ultimaBarra)
		{
			pathArchivo[i]=pathInicial[i];
			i++;
		}
		pathArchivo[i]='\0';

		i++;
		while(pathInicial[i] != NULL)
		{
			nombreArchivo[k]=pathInicial[i];
			i++;
			k++;
		}
		nombreArchivo[k]='\0';

		clusterDir = obtenerClusterInicial(pathArchivo);

	} else
	{
		memcpy(nombreArchivo, pathInicial, strlen(pathInicial));
		nombreArchivo[strlen(pathInicial)] = '\0';
		clusterDir = 2;
	}

	j=0;
	k=0;
	i=0;
	//Calculo nivel donde esta ubicado el archivo NUEVO
	while(nuevoNombre[k] != NULL)
	{
		if(nuevoNombre[k] == '/')
		{
			j++;
		}
		k++;
	}

	k=0;
	//Separo el nombre del directorio NUEVO y el archivo NUEVO si no es carpeta raiz
	if(j > 0)
	{
		ultimaBarra = strrchr(nuevoNombre,'/');
		while(nuevoNombre+i != ultimaBarra)
		{
			pathNuevo[i]=nuevoNombre[i];
			i++;
		}
		pathNuevo[i]='\0';

		i++;
		while(nuevoNombre[i] != NULL)
		{
			nombreNuevo[k]=nuevoNombre[i];
			i++;
			k++;
		}
		nombreNuevo[k]='\0';

		clusterDirNuevo = obtenerClusterInicial(pathNuevo);

	} else
	{
		memcpy(nombreNuevo, nuevoNombre, strlen(nuevoNombre));
		nombreNuevo[strlen(nuevoNombre)] = '\0';
		clusterDirNuevo = 2;
	}

	//Obtengo la data del cluster entero
	unsigned char *cluster;
	cluster = leerClusterDataRegion(clusterDir);

	nombreCompleto = malloc (255);
	entrada_utf16 = malloc(26);
	entrada_utf8 = malloc(26);
	//primerCluster = malloc(4);

	*nombreCompleto = '\0';
	*entrada_utf16 = '\0';
	*entrada_utf8 = '\0';
	/**primerCluster = '\0';*/


	//Voy avanzando de entrada en entrada (o sea de a 32 Bytes) hasta obtener el nombre completo
	i = 0;
	while (cluster[i] != 0x00 && i <= (*bs.secperclus*BYTESPERSEC))
	{
		if(cluster[i] == 0x2E || cluster[i] == 0xE5) //entrada '.' o '..' o eliminada
		{
			//Avanzo de entrada
			i += 32;
			continue;
		}

		j = i;
		//leo los bytes que contienenen al nombre
		memcpy(entrada_utf16, cluster + i + 1, 10);
		memcpy(entrada_utf16 + 10, cluster + i + 14, 12);
		memcpy(entrada_utf16 + 22, cluster + i + 28, 4);

		//Convierto a UTF8 y lo invierto
		unicode_utf16_to_utf8_inbuffer(entrada_utf16, 26, entrada_utf8, &longitudUTF8);
		strrev(entrada_utf8);

		//Voy acumulando el nombre de forma invertida
		memcpy(nombreCompleto + longitudParcial, entrada_utf8, strlen(entrada_utf8));
		nombreCompleto[longitudParcial + strlen(entrada_utf8)] = '\0';
		longitudParcial = strlen(nombreCompleto);

		*entrada_utf16 = '\0';
		*entrada_utf8 = '\0';

		//El bit 0 en 1 indica comienzo del nombre (que es la ultima entrada lfn)
		if(cluster[i] == 1 || cluster[i] == 0x41)
		{
			k = i;
			y = 0;
			//doy vuelta el nombre
			strrev(nombreCompleto);
			while(cluster[i+y+1] != 0x00 && y < 10)
			{
				y += 2;
			}
			while(cluster[i+4+y] != 0x00 && y >= 10 && y < 22)
			{
				y += 2;
			}
			while(cluster[i+6+y] != 0x00 && y >= 22 && y < 26)
			{
				y += 2;
			}
			y = y/2;
			nombreCompleto[y] = '\0';
			if(strcmp(nombreCompleto,nombreArchivo) == 0)
			{
				break;

			}
		}

		//Avanzo de entrada
		i += 32;

	}

	//Obtengo entrada de directorio
	struct fat_dir_entry *entradaDirectorio;
	int32_t tamanioCluster = *bs.secperclus * BYTESPERSEC;
	int32_t clusterDirectorio,numeroBytesEntradaCluster;

	entradaDirectorio = obtenerEntradaDataRegion(pathInicial, &clusterDirectorio, &numeroBytesEntradaCluster);

	//elimino todas las entradas de ese lfn
	while(j<= k)
	{
		eliminarEntradaDataRegion(cluster, j);
		j+=32;
	}

	//elimino la siguiente, que va a ser entrada de dir
	i+=32;
	eliminarEntradaDataRegion(cluster, i);
	i+=32;

	//todo falta ver que pasa si el cluster esta lleno
	//Este es el caso en que haya que mover a otra carpeta
	if(clusterDir != clusterDirNuevo)
	{
		EscribirClusterDataRegion(clusterDir, cluster);
		clusterDir = clusterDirNuevo;
		cluster = leerClusterDataRegion(clusterDir);
		i = 0;
	}

	//leo entradas hasta encontrar las que necesite seguidas, libres
	int32_t tamCluster;
	tamCluster = *bs.secperclus * BYTESPERSEC;
	while (i < tamCluster)
	{
		if((cluster[i] == 0x00 || cluster[i] == 0xE5) && (cluster[i+32] == 0x00 || cluster[i+32] == 0xE5))
			break;

		i+=32;
	}

	//armo lfn
	int32_t longitudUTF16 = 0;
	uint16_t nombre_utf16[14];

	cluster[i] = 0x41;
	int32_t h = 0;

	unicode_utf8_to_utf16_inbuffer(nombreNuevo, strlen(nombreNuevo)+1, nombre_utf16, &longitudUTF16);

	longitudUTF16--;
	while(h < longitudUTF16 && h < 5)
	{
		memcpy(cluster+i+1+(h*2), &nombre_utf16[h], 2);
		h++;
	}
	if(h==longitudUTF16)
	{
		cluster[i + 1 + (h*2)] = 0x00;
		cluster[i + 1 + (h*2) + 1] = 0x00;
		h++;
	}
	while(h > longitudUTF16 && h < 5)
	{
		cluster[i + 1 + (h*2)] = 0xFF;
		cluster[i + 1 + (h*2) + 1] = 0xFF;
		h++;
	}

	while(h < longitudUTF16 && h < 11)
	{
		memcpy(cluster+i+14+(h-5)*2, &nombre_utf16[h], 2);
		h++;
	}
	if(h==longitudUTF16)
	{
		cluster[i + 14 + (h-5)*2] = 0x00;
		cluster[i + 14 + (h-5)*2 + 1] = 0x00;
		h++;
	}
	while(h > longitudUTF16 && h < 11)
	{
		cluster[i + 14 + (h-5)*2] = 0xFF;
		cluster[i + 14 + (h-5)*2 + 1] = 0xFF;
		h++;
	}
	while(h < longitudUTF16 && h < 13)
	{
		memcpy(cluster+i+28+(h-11)*2, &nombre_utf16[h], 2);
		h++;
	}
	if(h==longitudUTF16)
	{
		cluster[i + 28 + (h-11)*2] = 0x00;
		cluster[i + 28 + (h-11)*2 + 1] = 0x00;
		h++;
	}
	while(h > longitudUTF16 && h < 13)
	{
		cluster[i + 28 + (h-11)*2] = 0xFF;
		cluster[i + 28 + (h-11)*2 + 1] = 0xFF;
		h++;
	}

	cluster[i + 11] = 0x0F;
	cluster[i + 12] = 0x00;
	cluster[i + 13] = 0x00;
	cluster[i + 26] = 0x00;
	cluster[i + 27] = 0x00;

	i+=32;

	//armo entrada de directorio


	char **split;
	split = string_split2(nombreNuevo,'.');
	memcpy(cluster + i, convertirMayusculas(split[0]), 8);
	memcpy(cluster + i + 8, convertirMayusculas(split[1]), 3);
	cluster[i + 11] = entradaDirectorio->Attr;
	cluster[i + 12] = 0x00;
	cluster[i + 13] = 0x00;
	cluster[i + 14] = 0x00;
	cluster[i + 15] = 0x00;
	cluster[i + 16] = 0x00;
	cluster[i + 17] = 0x00;
	cluster[i + 18] = 0x00;
	cluster[i + 19] = 0x00;
	char *contenido = malloc(2);
	SET_16BIT_WORD(contenido, 0, entradaDirectorio->FstClusHI);
	memcpy(cluster + i + 20, contenido, 2 );
	cluster[i + 22] = 0x00;
	cluster[i + 23] = 0x00;
	cluster[i + 24] = 0x00;
	cluster[i + 25] = 0x00;

	SET_16BIT_WORD(contenido, 0, entradaDirectorio->FstClusLO);
	memcpy(cluster + i + 26, contenido, 2 );
	free(contenido);
	contenido = malloc(4);
	SET_32BIT_WORD(contenido, 0, entradaDirectorio->FileSize);
	memcpy(cluster + i + 28, contenido, 4 );

	//grabo todas las nuevas entradas
	EscribirClusterDataRegion(clusterDir, cluster);

	free(contenido);
	free(nombreCompleto);
	free(nombreNuevo);
	free(entrada_utf16);
	free(entrada_utf8);
	free(pathArchivo);
	free(entradaDirectorio);
	free(nombreArchivo);
	free(pathNuevo);

	//ver que pasa si no hay espacio


	return 0;
}


struct cluster *listaClustersEncadenados(int32_t primerCluster, int32_t *cantidadClusters)
{
	*cantidadClusters = 1;
	int32_t siguiente;
	struct cluster *pri = NULL, *ult = NULL;

	//Bloqueo semaforo de Fat Region
	pthread_mutex_lock(&semaforoFatRegion);

	//Creo la lista
	ult = creaColaCluster(ult,primerCluster);
	pri = ult;

	//recorro y voy agregando a la lista
	siguiente = leerClusterFATRegion(primerCluster);
	while(siguiente != 0x0FFFFFFF)
	{
		ult = creaColaCluster(ult,siguiente);
		(*cantidadClusters) ++;
		siguiente = leerClusterFATRegion(siguiente);
	}

	//Desbloqueo semaforo de Fat Region
	pthread_mutex_unlock(&semaforoFatRegion);

	return pri;

}


int32_t obtenerClusterLibre()
{
	int32_t clusterLibre = -1;
	int32_t i;
	int32_t cantEntradasFatRegion = (GET_32BIT_WORD(bs.fatsz32, 0) * BYTESPERSEC) / 4;

	//Recorre todas las entradas hasta que encuentra la que esta libre
	//Las primeras 2 (0 y 1) estan reservadas
	for (i=2; i < cantEntradasFatRegion; i++)
	{
		if (leerClusterFATRegion(i) == 0x0)
		{
			clusterLibre = i;
			break;
		}
	}

	return clusterLibre;
}

int32_t *agregarClusterACadena(int32_t primerCluster)
{
	int32_t cluster = primerCluster;
	int32_t clusterLibre = -1;
	int32_t siguiente;
	int32_t retorno = -1;

	//Inicializo cluster Data Region en 0
	unsigned char *data;
	data = malloc(*bs.secperclus * BYTESPERSEC);
	memset(data, 0, *bs.secperclus * BYTESPERSEC);

	clusterLibre = obtenerClusterLibre();

	char *contenido;
	contenido = malloc(sizeof(char)*4);

	if(clusterLibre != -1)
	{
		//preguntamos por cadena existente
		if(primerCluster != -1)
		{
			//recorremos hasta entonctrar ultimo cluster de la cadena
			siguiente = leerClusterFATRegion(cluster);
			while(siguiente != 0x0FFFFFFF)
			{
				cluster = siguiente;
				siguiente = leerClusterFATRegion(cluster);
			}


			//al ultimo cluster de cadena le grabo el numCluster
			SET_32BIT_WORD(contenido, 0, clusterLibre);
			EscribirEntradaFatRegion(cluster,  contenido);
		}
		//exista la cadena o la este empezando ahora, al nuevoCluster le grabo EOC
		SET_32BIT_WORD(contenido, 0, 0x0FFFFFFF);
		retorno = EscribirEntradaFatRegion(clusterLibre, contenido);
		EscribirClusterDataRegion(clusterLibre,data);
	}

	free(data);
	free(contenido);

	return clusterLibre;

}



int32_t *eliminarClusterDeCadena(int32_t primerCluster)
{
	int32_t cluster = primerCluster;
	int32_t clusterAnterior = -1;
	int32_t clusterSiguiente = 0;

	char *contenido;
	contenido = malloc(sizeof(char)*4);

	//recorrer cadena hasta entonctrar ultimo cluster de la cadena
	clusterSiguiente = leerClusterFATRegion(cluster);
	while(clusterSiguiente != 0x0FFFFFFF)
	{
		clusterAnterior = cluster;
		cluster =clusterSiguiente;
		clusterSiguiente = leerClusterFATRegion(cluster);
	}

	//al anterior al ultimo, si habia mas de 1 en la cadena, lo grabamos como EOC
	if(clusterAnterior != -1){
		SET_32BIT_WORD(contenido, 0, 0x0FFFFFFF);
		EscribirEntradaFatRegion(clusterAnterior,  contenido);
	}
	//al ultimo lo grabamos como libre
	SET_32BIT_WORD(contenido, 0, 0x0);
	EscribirEntradaFatRegion(cluster,  contenido);

	free(contenido);

	return 1;
}

int32_t obtenerCantidadClustersLibres()
{
	int32_t cantClustersLibres = 0;
	int32_t i;
	int32_t cantEntradasFatRegion = (GET_32BIT_WORD(bs.fatsz32, 0) * BYTESPERSEC) / 4;

	//Bloqueo semaforo de Fat Region
	pthread_mutex_lock(&semaforoFatRegion);

	//Recorre todas las entradas y suma las que estan libres
	//Las primeras 2 (0 y 1) estan reservadas
	for (i=2; i < cantEntradasFatRegion; i++)
	{
		if (leerClusterFATRegion(i) == 0x0)
		{
			cantClustersLibres ++;
		}
	}

	//Desbloqueo semaforo de Fat Region
	pthread_mutex_unlock(&semaforoFatRegion);

	return cantClustersLibres;

}

int32_t obtenerDireccionCluster(int32_t numCluster) //Devuelve el sector
{
	//Devuelve el numero de sector en el que esta el cluster
	//SectoresReservados + CantidadDeFATs * TamañoDeLasFAT + ((NumeroDeCluster - 2) * SectoresPorCluster)
	int32_t posCluster;
	posCluster = *bs.rsvdseccnt + *bs.numfats * GET_32BIT_WORD(bs.fatsz32, 0) + ((numCluster -2) * *bs.secperclus);

	return posCluster;

}



int32_t load_bootsector()
{
	unsigned char *boot_sector;

	boot_sector = obtenerBloque(0);

	memcpy(bs.jmpboot, boot_sector+ BS_JMPBOOT, 3);
	memcpy(bs.oemname, boot_sector+ BS_OEMNAME, 8);
	memcpy(bs.bytspersec, boot_sector+ BPB_BYTSPERSEC, 2);
	memcpy(bs.secperclus, boot_sector+ BPB_SECPERCLUS, 1);
	memcpy(bs.rsvdseccnt, boot_sector+ BPB_RSVDSECCNT, 2);
	memcpy(bs.numfats, boot_sector+ BPB_NUMFATS, 1);
	memcpy(bs.rootentcnt, boot_sector+ BPB_ROOTENTCNT, 2);
	memcpy(bs.totsec16, boot_sector+ BPB_TOTSEC16, 2);
	memcpy(bs.media, boot_sector+ BPB_MEDIA, 1);
	memcpy(bs.fatsz16, boot_sector+ BPB_FATSZ16, 2);
	memcpy(bs.secpertrk, boot_sector+ BPB_SECPERTRK, 2);
	memcpy(bs.numheads, boot_sector+ BPB_NUMHEADS, 2);
	memcpy(bs.hiddsec, boot_sector+ BPB_HIDDSEC, 4);
	memcpy(bs.totsec32, boot_sector+ BPB_TOTSEC32, 4);
	memcpy(bs.fatsz32, boot_sector+ BPB_FAT32_FATSZ32, 4);

	free(boot_sector);
	return 1;

}

struct cluster *nuevoNodoCluster()
{
	struct cluster *p;
	p=(struct cluster *)malloc (sizeof(struct cluster));
	if(p==NULL)
	{
		printf("Memoria RAM Llena");
		if(config.loguear == 1)
		{
			int pid = getpid();
			logMessage("nuevoNodoCluster",pid,0,3,"Memoria RAM Llena");
		}
		exit(0);
	}
	return p;
}

struct cluster *creaColaCluster(struct cluster *ult, int32_t x)
{
	struct cluster *p;
	p=nuevoNodoCluster();
	(*p).numCluster=x;
	(*p).sgt=NULL;
	if(ult!=NULL) (*ult).sgt=p; // Si hay nodo anterior en prox pongo la direccion del nodo actual
	return p;
}

struct nodoLFN *nuevoNodoLFN()
{
	struct nodoLFN *p;
	p=(struct nodoLFN *)malloc (sizeof(struct nodoLFN));
	if(p==NULL)
	{
		printf("Memoria RAM Llena");
		if(config.loguear == 1)
		{
			int pid = getpid();
			logMessage("Listando directorio",pid,0,3,"Memoria RAM Llena");
		}
		exit(0);
	}
	return p;
}

struct nodoLFN *creaColaLFN(struct nodoLFN *ult, char *nombre)
{
	struct nodoLFN *p;
	p=nuevoNodoLFN();
	memcpy(p->nombre,nombre,strlen(nombre));
	p->nombre[strlen(nombre)] = '\0';
	(*p).sgt=NULL;
	if(ult!=NULL) (*ult).sgt=p; // Si hay nodo anterior en prox pongo la direccion del nodo actual
	return p;
}

void fsinfo()
{
	int32_t cantClustersData;
	int32_t cantClustersLibres;
	int32_t cantClustersOcupados;
	int32_t tamSec;
	int32_t tamCluster;
	int32_t tamFAT;
	cantClustersData = (GET_32BIT_WORD(bs.fatsz32, 0) * BYTESPERSEC) / 4 - 2;
	cantClustersLibres = obtenerCantidadClustersLibres();
	cantClustersOcupados = cantClustersData - cantClustersLibres;
	tamSec = BYTESPERSEC;
	tamCluster = *bs.secperclus * BYTESPERSEC;
	tamFAT = (GET_32BIT_WORD(bs.fatsz32, 0) * BYTESPERSEC) / 1024;
	printf("Cantidad Clusters Ocupados: %d\nCantidad Clusters Libres: %d\nTamano de un sector: %d bytes\nTamano de un cluster: %d bytes\nTamano de FAT: %d kilobytes\n", cantClustersOcupados, cantClustersLibres, tamSec, tamCluster, tamFAT);

	//Informo en el log
	if(config.loguear == 1)
	{
		int pid = getpid();
		logMessage("fsinfo",pid,0,0,"Se informaron parametros del filesystem correctamente");
	}
}

void listarClusters(struct cluster *listaClusters, int32_t cantidadClusters)
{
	int32_t i;
	i = 0;

	printf("#Clusters:\n");

	if(cantidadClusters >= 20)
	{
		while(i < 19)
		{
			printf("%d,  ", listaClusters->numCluster);
			listaClusters = listaClusters->sgt;
			i++;
		}
	}
	else
	{
		while(i < cantidadClusters-1)
		{
			printf("%d,  ", listaClusters->numCluster);
			listaClusters = listaClusters->sgt;
			i++;
		}
	}
	printf("%d.\n", listaClusters->numCluster);
}

void finfo(char *path)
{
	int32_t clusterInicial;
	int32_t cantidadClusters;
	cantidadClusters = 0;
	struct cluster *listaClusters;

	//Obtengo el primer nro de cluster del archivo o directorio
	clusterInicial = obtenerClusterInicial(path);


	if(clusterInicial == 2)
	{
		printf("El directorio/archivo no tiene clusters asociados");
		if(config.loguear == 1)
		{
			int pid = getpid();
			logMessage("finfo",pid,0,2,"El directorio/archivo solicitado no tiene clusters asociados");
		}
	}
	else
	{
		//Obtengo la lista de clusters del archivo o directorio
		listaClusters = listaClustersEncadenados(clusterInicial, &cantidadClusters);
		listarClusters(listaClusters, cantidadClusters);
	}
}




int32_t crearArchivo(char *pathArchivo)
{
	char **split;
	int j = 0;
	int i = 0;
	int k = 0;
	char *pathDirectorio;
	pathDirectorio = malloc(255);
	char *nombreArchivo;
	nombreArchivo = malloc(13);
	nombreArchivo[0] = '\0';
	unsigned char *cluster;
	int32_t clusterDir;

	//Calculo nivel donde esta ubicado el archivo
	while(pathArchivo[k] != NULL)
	{
		if(pathArchivo[k] == '/')
		{
			j++;
		}
		k++;
	}

	k=0;
	//Separo el nombre del directorio y el archivo si no es carpeta raiz
	if(j > 0)
	{
		char *ultimaBarra = strrchr(pathArchivo,'/');
		while(pathArchivo+i != ultimaBarra)
		{
			pathDirectorio[i]=pathArchivo[i];
			i++;
		}
		pathDirectorio[i]='\0';

		i++;
		while(pathArchivo[i] != NULL)
		{
			nombreArchivo[k]=pathArchivo[i];
			i++;
			k++;
		}
		nombreArchivo[k]='\0';

		clusterDir = obtenerClusterInicial(pathDirectorio);

	}
	else
	{
		memcpy(nombreArchivo,pathArchivo,strlen(pathArchivo));
		nombreArchivo[strlen(pathArchivo)] = '\0';
		clusterDir = 2;
	}

	cluster = leerClusterDataRegion(clusterDir);

	//Busco dos entradas seguidas libres

	i=0;
	int32_t tamCluster;
	tamCluster = *bs.secperclus * BYTESPERSEC;
	while (i < tamCluster)
	{
		if((cluster[i] == 0x00 || cluster[i] == 0xE5) && (cluster[i+32] == 0x00 || cluster[i+32] == 0xE5))
			break;
		i+=32;
	}

	//armo lfn
	int32_t longitudUTF16 = 0;
	uint16_t entrada_utf16[14];

	cluster[i] = 0x41;
	int32_t h = 0;

	unicode_utf8_to_utf16_inbuffer(nombreArchivo, strlen(nombreArchivo)+1, entrada_utf16, &longitudUTF16);

	longitudUTF16--;
	while(h < longitudUTF16 && h < 5)
	{
		memcpy(cluster+i+1+(h*2), &entrada_utf16[h], 2);
		h++;
	}
	if(h==longitudUTF16)
	{
		cluster[i + 1 + (h*2)] = 0x00;
		cluster[i + 1 + (h*2) + 1] = 0x00;
		h++;
	}
	while(h > longitudUTF16 && h < 5)
	{
		cluster[i + 1 + (h*2)] = 0xFF;
		cluster[i + 1 + (h*2) + 1] = 0xFF;
		h++;
	}

	while(h < longitudUTF16 && h < 11)
	{
		memcpy(cluster+i+14+(h-5)*2, &entrada_utf16[h], 2);
		h++;
	}
	if(h==longitudUTF16)
	{
		cluster[i + 14 + (h-5)*2] = 0x00;
		cluster[i + 14 + (h-5)*2 + 1] = 0x00;
		h++;
	}
	while(h > longitudUTF16 && h < 11)
	{
		cluster[i + 14 + (h-5)*2] = 0xFF;
		cluster[i + 14 + (h-5)*2 + 1] = 0xFF;
		h++;
	}
	while(h < longitudUTF16 && h < 13)
	{
		memcpy(cluster+i+28+(h-11)*2, &entrada_utf16[h], 2);
		h++;
	}
	if(h==longitudUTF16)
	{
		cluster[i + 28 + (h-11)*2] = 0x00;
		cluster[i + 28 + (h-11)*2 + 1] = 0x00;
		h++;
	}
	while(h > longitudUTF16 && h < 13)
	{
		cluster[i + 28 + (h-11)*2] = 0xFF;
		cluster[i + 28 + (h-11)*2 + 1] = 0xFF;
		h++;
	}

	cluster[i + 11] = 0x0F;
	cluster[i + 12] = 0x00;
	cluster[i + 13] = 0x00;
	cluster[i + 26] = 0x00;
	cluster[i + 27] = 0x00;

	i+=32;

	//armo entrada de directorio
	int32_t cantCaracteres;

	split = string_split2(nombreArchivo,'.');

	cantCaracteres = strlen(split[0]);
	memcpy(cluster + i, convertirMayusculas(split[0]), 8);
	memcpy(cluster + i + cantCaracteres, "        ", 8 - cantCaracteres);
	memcpy(cluster + i + 8, convertirMayusculas(split[1]), 3);
	cluster[i + 11] = 0x20;
	cluster[i + 12] = 0x00;
	cluster[i + 13] = 0x00;
	cluster[i + 14] = 0x00;
	cluster[i + 15] = 0x00;
	cluster[i + 16] = 0x00;
	cluster[i + 17] = 0x00;
	cluster[i + 18] = 0x00;
	cluster[i + 19] = 0x00;
	cluster[i + 20] = 0x00;
	cluster[i + 21] = 0x00;
	cluster[i + 22] = 0x00;
	cluster[i + 23] = 0x00;
	cluster[i + 24] = 0x00;
	cluster[i + 25] = 0x00;
	cluster[i + 26] = 0x00;
	cluster[i + 27] = 0x00;
	cluster[i + 28] = 0x00;
	cluster[i + 29] = 0x00;
	cluster[i + 30] = 0x00;
	cluster[i + 31] = 0x00;

	//grabo todas las nuevas entradas
	EscribirClusterDataRegion(clusterDir, cluster);

	free(pathDirectorio);
	free(nombreArchivo);
	return 0;
}

int32_t crearDirectorio(char *path)
{
	int j = 0;
	int i = 0;
	int k = 0;
	unsigned char *pathDirectorio;
	pathDirectorio = (unsigned char *) malloc(255);
	unsigned char *nombreDir;
	nombreDir = (unsigned char *) malloc(13);
	//memcpy(nombreDir, '\0', 1);
	nombreDir[0] = '\0';
	unsigned char *cluster;
	int32_t clusterDir;

	//Calculo nivel donde esta ubicado el archivo
	while(path[k] != NULL)
	{
		if(path[k] == '/')
		{
			j++;
		}
		k++;
	}

	k=0;
	//Separo el nombre del directorio y el archivo si no es carpeta raiz
	if(j > 0)
	{
		unsigned char *ultimaBarra = strrchr(path,'/');
		while(path+i != ultimaBarra)
		{
			pathDirectorio[i]=path[i];
			i++;
		}
		pathDirectorio[i]='\0';

		i++;
		while(path[i] != NULL)
		{
			nombreDir[k]=path[i];
			i++;
			k++;
		}
		nombreDir[k]='\0';

		clusterDir = obtenerClusterInicial(pathDirectorio);

	} else
	{
		memcpy(nombreDir,path,strlen(path));
		nombreDir[strlen(path)] = '\0';
		clusterDir = 2;
	}

	cluster = leerClusterDataRegion(clusterDir);

	//Busco dos entradas seguidas libres
	i=0;
	int32_t tamCluster;
	tamCluster = *bs.secperclus * BYTESPERSEC;
	while (i < tamCluster)
	{
		if((cluster[i] == 0x00 || cluster[i] == 0xE5) && (cluster[i+32] == 0x00 || cluster[i+32] == 0xE5))
			break;
		i+=32;
	}

	//armo lfn
	int32_t longitudUTF16 = 0;
	uint16_t entrada_utf16[14];

	cluster[i] = 0x41;
	int32_t h = 0;

	unicode_utf8_to_utf16_inbuffer(nombreDir, strlen(nombreDir)+1, entrada_utf16, &longitudUTF16);

	longitudUTF16--;
	while(h < longitudUTF16 && h < 5)
	{
		memcpy(cluster+i+1+(h*2), &entrada_utf16[h], 2);
		h++;
	}
	if(h==longitudUTF16)
	{
		cluster[i + 1 + (h*2)] = 0x00;
		cluster[i + 1 + (h*2) + 1] = 0x00;
		h++;
	}
	while(h > longitudUTF16 && h < 5)
	{
		cluster[i + 1 + (h*2)] = 0xFF;
		cluster[i + 1 + (h*2) + 1] = 0xFF;
		h++;
	}

	while(h < longitudUTF16 && h < 11)
	{
		memcpy(cluster+i+14+(h-5)*2, &entrada_utf16[h], 2);
		h++;
	}
	if(h==longitudUTF16)
	{
		cluster[i + 14 + (h-5)*2] = 0x00;
		cluster[i + 14 + (h-5)*2 + 1] = 0x00;
		h++;
	}
	while(h > longitudUTF16 && h < 11)
	{
		cluster[i + 14 + (h-5)*2] = 0xFF;
		cluster[i + 14 + (h-5)*2 + 1] = 0xFF;
		h++;
	}
	while(h < longitudUTF16 && h < 13)
	{
		memcpy(cluster+i+28+(h-11)*2, &entrada_utf16[h], 2);
		h++;
	}
	if(h==longitudUTF16)
	{
		cluster[i + 28 + (h-11)*2] = 0x00;
		cluster[i + 28 + (h-11)*2 + 1] = 0x00;
		h++;
	}
	while(h > longitudUTF16 && h < 13)
	{
		cluster[i + 28 + (h-11)*2] = 0xFF;
		cluster[i + 28 + (h-11)*2 + 1] = 0xFF;
		h++;
	}

	cluster[i + 11] = 0x0F;
	cluster[i + 12] = 0x00;
	cluster[i + 13] = 0x00;
	cluster[i + 26] = 0x00;
	cluster[i + 27] = 0x00;

	i+=32;

	//armo entrada de directorio

	//Bloqueo semaforo de Fat Region
	pthread_mutex_lock(&semaforoFatRegion);

	//int32_t clusterLibre = obtenerClusterLibre();
	int32_t clusterLibre = agregarClusterACadena(-1);//(-1: Crea nueva cadena) devuelve el cluster que agrego
	if(clusterLibre == -1)
	{
		//No pudo crear la cadena

		//Desbloqueo semaforo de Fat Region
		pthread_mutex_unlock(&semaforoFatRegion);

		return 1; //Error
	}

	//Flush de la fat region
	fat_flush();

	//Desbloqueo semaforo de Fat Region
	pthread_mutex_unlock(&semaforoFatRegion);

	unsigned short clusterLO;
	unsigned short clusterHI;
	clusterLO = clusterLibre & 0x0000FFFF;
	clusterHI = clusterLibre >> 16;

	memcpy(cluster + i, convertirMayusculas(nombreDir), strlen(nombreDir));
	memcpy(cluster + i + strlen(nombreDir), "        ", 8-strlen(nombreDir));
	memcpy(cluster + i + 8, "   ", 3);
	cluster[i + 11] = 0x10;
	cluster[i + 12] = 0x00;
	cluster[i + 13] = 0x00;
	cluster[i + 14] = 0x00;
	cluster[i + 15] = 0x00;
	cluster[i + 16] = 0x00;
	cluster[i + 17] = 0x00;
	cluster[i + 18] = 0x00;
	cluster[i + 19] = 0x00;
	char *cont = malloc(2);
	SET_16BIT_WORD(cont, 0, clusterHI);
	memcpy(cluster + i + 20, cont, 2 );
	cluster[i + 22] = 0x00;
	cluster[i + 23] = 0x00;
	cluster[i + 24] = 0x00;
	cluster[i + 25] = 0x00;
	SET_16BIT_WORD(cont, 0, clusterLO);
	memcpy(cluster + i + 26, cont, 2 );
	free(cont);
	cluster[i + 28] = 0x00;
	cluster[i + 29] = 0x00;
	cluster[i + 30] = 0x00;
	cluster[i + 31] = 0x00;



	//grabo todas las nuevas entradas
	EscribirClusterDataRegion(clusterDir, cluster);

	/*//Grabo la entrada en la FAT correspondiente al directorio creado
	char *contenido;
	contenido = malloc(4);
	SET_32BIT_WORD(contenido, 0, 0x0FFFFFFF);
	EscribirEntradaFatRegion(clusterLibre, contenido);*/

	//free(contenido);
	free(pathDirectorio);
	free(nombreDir);
	return 0;
}

int32_t borrarArchivo(char *path)
{
	struct fat_dir_entry *directoryEntry;
	int32_t clusterDirectorio,numeroBytesEntradaCluster;
	unsigned char *cluster;

	//Busco la entrada de directorio del archivo a borrar
	directoryEntry = obtenerEntradaDataRegion(path,&clusterDirectorio, &numeroBytesEntradaCluster);
	//Traigo el cluster en el que se encuentra
	cluster = leerClusterDataRegion(clusterDirectorio);

	cluster[numeroBytesEntradaCluster] = 0xE5;
	cluster[numeroBytesEntradaCluster-32] = 0xE5;
	int32_t clusterInicial;
	if(directoryEntry->FileSize > 0)
	{

		truncarArchivo(path,0, &clusterInicial);
	}

	EscribirClusterDataRegion(clusterDirectorio, cluster);

	return 0;
}

int32_t borrarDirectorio(char *path)
{
	struct fat_dir_entry *directoryEntry;
	int32_t clusterDirectorio,clusterPadre,numeroBytesEntradaCluster;
	unsigned char *cluster;
	unsigned char *clusterDir;
	int32_t tieneAlgo = 0;
	int32_t i = 0;
	int32_t tamCluster;
	tamCluster = *bs.secperclus * BYTESPERSEC;

	//Busco la entrada de directorio del directorio a borrar
	directoryEntry = obtenerEntradaDataRegion(path,&clusterPadre, &numeroBytesEntradaCluster);
	clusterDirectorio = swap_uint32(directoryEntry->FstClusHI) + directoryEntry->FstClusLO;
	//Traigo el cluster en el que se encuentra
	cluster = leerClusterDataRegion(clusterPadre);
	clusterDir = leerClusterDataRegion(clusterDirectorio);

	while(i<tamCluster && clusterDir[i]!=0x00)
	{
		if(clusterDir[i]!=0xE5)
		{
			tieneAlgo = 1;
			break;
		}
		i+=32;
	}
	if(tieneAlgo==0)
	{
		cluster[numeroBytesEntradaCluster] = 0xE5;
		cluster[numeroBytesEntradaCluster-32] = 0xE5;

		EscribirClusterDataRegion(clusterPadre, cluster);
		eliminarClusterDeCadena(clusterDirectorio);
	}
	else if (config.loguear ==  1)
	{
		int pid;
		pid = getpid();
		logMessage("borrarDirectorio",pid,0,2,"El directorio que desea borrar posee archivos o directorios");
	}

	return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

